﻿using System;
using System.Diagnostics;
using System.Linq;
using NHibernate;
using NHibernate.Linq;

namespace NHDay_Linq.Repository
{
	public class Repository<T> : IDisposable
	{
		protected ISessionFactory _factory = null;
		protected ISession _session = null;
		protected ITransaction _transaction = null;

		public Repository(ISessionFactory factory)
		{
			_factory = factory;
			_session = _factory.OpenSession();
		}

		public Repository(ISession session)
		{
			_session = session;
		}

		#region Transaction and Session Management Methods

		public void BeginTransaction()
		{
			_transaction = _session.BeginTransaction();
		}

		public void CommitTransaction()
		{
			// _transaction will be replaced with a new transaction
			// by NHibernate, but we will close to keep a consistent state.
			_transaction.Commit();

			CloseTransaction();
		}

		public void RollbackTransaction()
		{
			// _session must be closed and disposed after a transaction
			// rollback to keep a consistent state.
			_transaction.Rollback();

			CloseTransaction();
			CloseSession();
		}

		private void CloseTransaction()
		{
			_transaction.Dispose();
			_transaction = null;
		}

		private void CloseSession()
		{
			if (_factory != null)
			{
				_session.Close();
				_session.Dispose();
				_session = null;
			}
		}

		#endregion

		#region IRepository Members

		public virtual void Save(T obj)
		{
			_session.SaveOrUpdate(obj);
		}

		public virtual void Delete(T obj)
		{
			_session.Delete(obj);
		}

		public virtual object GetById(object objId)
		{
			return _session.Load<T>(objId);
		}

		public virtual IQueryable<T> Query()
		{
			return _session.Query<T>();
		}

		#endregion

		#region IDisposable Members

		public void Dispose()
		{
			if (_transaction != null)
			{
				// Commit transaction by default, unless user explicitly rolls it back.
				// To rollback transaction by default, unless user explicitly commits,
				// comment out the line below.
				CommitTransaction();
				Debug.WriteLine("Repository Transaction Commit completed");
			}

			if (_session != null)
			{
				_session.Flush(); // commit session transactions
				Debug.WriteLine("Repository Session Flush");
				CloseSession();
			}
		}

		#endregion
	}
}
